/*
 * Copyright (c) 2012, Marcin Czekaj
 * All rights reserved.
 *
 * This software is open-source under the BSD license; see LICENSE.TXT for a description.
 */
package pl.edu.uj.fais.graph.io;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;

import org.apache.commons.collections15.Transformer;

import pl.edu.uj.fais.graph.elements.Link;
import pl.edu.uj.fais.graph.elements.Node;
import pl.edu.uj.fais.mode.GraphMode;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Hypergraph;
import edu.uci.ics.jung.graph.SetHypergraph;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.io.GraphMLWriter;

public class HyperGraphWriter {
    
    private File file;
    
    public HyperGraphWriter(File file) {
        this.file = file;
    }
    
    // @formatter:off
    public void save(Graph<Node, Link> graph, GraphMode graphMode, boolean includeData)
            throws IOException {
        
        Hypergraph<Node, Link> hyperGraph = graph;
        
        if (graphMode == GraphMode.HYPERGRAPH) {
            hyperGraph = toHyperGraph(graph);
        }
        
        PrintWriter fileWriter = new PrintWriter(new BufferedWriter(new FileWriter(file)));
        
        GraphMLWriter<Node, Link> writer = new GraphMLWriter<>();
        setVertexIDs(writer);
        
        if (includeData) {
	        setLabels(writer);
	        setPositions(writer);
        }
        
        writer.save(hyperGraph, fileWriter);
    }
    // @formatter:on
    
    private SetHypergraph<Node, Link> toHyperGraph(Graph<Node, Link> graph) {
        
        SetHypergraph<Node, Link> hyperGraph = new SetHypergraph<>();
        
        // add nodes
        for (Node node : graph.getVertices()) {
            if (!node.isProxyNode()) {
                hyperGraph.addVertex(node);
            }
        }
        
        // add links
        for (Node node : graph.getVertices()) {
            if (node.isProxyNode()) {
                hyperGraph.addEdge(new Link(),
                                   graph.getNeighbors(node),
                                   EdgeType.UNDIRECTED);
            }
        }
        
        return hyperGraph;
    }
    
    private void setVertexIDs(GraphMLWriter<Node, Link> writer) {
        writer.setVertexIDs(new Transformer<Node, String>() {
            
            @Override
            public String transform(Node node) {
                return "" + node.getId();
            }
        });
    }
    
    private void setLabels(GraphMLWriter<Node, Link> writer) {
        // @formatter:off
        writer.addVertexData("label", null, null,
                             new Transformer<Node, String>() {
                                 
                                 @Override
                                 public String transform(Node node) {
                                     return node.getLabel();
                                 }
                             });
        // @formatter:on
    }
    
    private void setPositions(GraphMLWriter<Node, Link> writer) {
        // @formatter:off
        writer.addVertexData("position", null, null,
                             new Transformer<Node, String>() {
                                 
                                 @Override
                                 public String transform(Node node) {
                                     return String.format(Locale.US,
                                                          "%f;%f",
                                                          node.getX(),
                                                          node.getY());
                                 }
                             });
        // @formatter:on
    }
}
